home *** CD-ROM | disk | FTP | other *** search
- /*-----------------------------------------------------------------------
- * FILE:
- * prs2define.c
- *
- * IDENTIFICATION:
- * $Header: /private/postgres/src/rules/prs2/RCS/prs2define.c,v 1.26 1992/07/08 20:51:28 joey Exp $
- *
- * DESCRIPTION:
- * All the routines needed to define a (tuple level) PRS2 rule
- */
-
- #include "tmp/postgres.h"
- #include "nodes/primnodes.h"
- #include "nodes/primnodes.a.h"
- #include "nodes/pg_lisp.h"
- #include "utils/log.h"
- #include "utils/relcache.h" /* RelationNameGetRelation() defined here...*/
- #include "rules/prs2.h"
- #include "access/skey.h" /* 'ScanKeyEntryData' defined here... */
- #include "access/tqual.h" /* 'NowTimeQual' defined here.. */
- #include "access/heapam.h" /* heap AM calls defined here */
- #include "utils/lsyscache.h" /* get_attnum() defined here...*/
- #include "parser/parse.h" /* RETRIEVE, APPEND etc defined here.. */
- #include "parser/parsetree.h"
- #include "catalog/catname.h" /* names of various system relations */
- #include "utils/fmgr.h" /* for F_CHAR16EQ, F_CHAR16IN etc. */
- #include "access/ftup.h" /* for FormHeapTuple() */
- #include "utils/palloc.h"
-
- #include "catalog/pg_proc.h"
- #include "catalog/pg_prs2rule.h"
- #include "catalog/pg_prs2plans.h"
-
- extern LispValue planner();
- extern LispValue lispCopy();
-
-
- /*-----------------------------------------------------------------------
- *
- * prs2DefineTupleRule
- *
- * Define a tuple-level rule. This is the high-level interface.
- *
- *-----------------------------------------------------------------------
- */
-
- void
- prs2DefineTupleRule(parseTree, ruleText)
- LispValue parseTree;
- char *ruleText;
- {
-
- Prs2RuleData ruleData;
- List hint;
-
- #ifdef PRS2_DEBUG
- printf("PRS2: ---prs2DefineTupleRule called, with argument =");
- lispDisplay(parseTree);
- printf("\n");
- printf("PRS2: ruletext = %s\n", ruleText);
- #endif PRS2_DEBUG
-
- /*
- * find the rule "hint", i.e. see if the user explicitly
- * stated what kind of lock he/she/it/ wnated to use.
- */
- hint = GetRuleHintFromParse(parseTree);
-
- /*
- * extract some rule info form the parsetree...
- */
- ruleData = prs2FindRuleData(parseTree, ruleText);
-
- /*
- * now put locks/stubs and update system catalogs...
- */
- prs2AddTheNewRule(ruleData, hint);
-
- #ifdef PRS2_DEBUG
- printf("PRS2: --- DEFINE PRS2 RULE: Done.\n");
- #endif PRS2_DEBUG
- }
-
- /*-----------------------------------------------------------------------
- * prs2RemoveTupleRule
- *
- * Remove a tuple-system rule given its name.
- *
- *-----------------------------------------------------------------------
- */
- void
- prs2RemoveTupleRule(ruleName)
- Name ruleName;
- {
- ObjectId ruleId;
-
- /*
- * first find its oid & then remove it...
- */
- ruleId = get_ruleid(ruleName);
- if (ruleId == InvalidObjectId) {
- elog(WARN, "Rule '%s' does not exist!", ruleName);
- }
-
- prs2DeleteTheOldRule(ruleId);
- }
-
- /*-----------------------------------------------------------------------
- * prs2FindRuleData
- *
- * create a 'Prs2RuleData' struct & fill it with all the information
- * about this rule we will ever need to know...
- *
- *-----------------------------------------------------------------------
- */
- Prs2RuleData
- prs2FindRuleData(parseTree, ruleText)
- List parseTree;
- char *ruleText;
- {
- Prs2RuleData r;
- List eventTarget;
- Relation rel;
- bool newUsed, currentUsed;
-
- /*
- * create the structure where we hold all the rule
- * information we need to know...
- */
- r = (Prs2RuleData) palloc(sizeof(Prs2RuleDataData));
- if (r==NULL) {
- elog(WARN, "prs2FindRuleInfo: Out of memory");
- }
- r->ruleName = (Name) palloc(sizeof(NameData));
- if (r->ruleName == NULL) {
- elog(WARN, "prs2FindRuleInfo: Out of memory");
- }
- r->eventRelationName = (Name) palloc(sizeof(NameData));
- if (r->eventRelationName == NULL) {
- elog(WARN, "prs2FindRuleInfo: Out of memory");
- }
- r->eventAttributeName = (Name) palloc(sizeof(NameData));
- if (r->eventAttributeName == NULL) {
- elog(WARN, "prs2FindRuleInfo: Out of memory");
- }
-
- /*
- * start filling it in...
- * NOTE: we do not know yet the rule oid...
- */
- r->ruleId = InvalidObjectId;
- r->parseTree = parseTree;
- r->ruleText = ruleText;
- strcpy(r->ruleName->data, CString(GetRuleNameFromParse(parseTree)));
-
- if (CInteger(GetRuleInsteadFromParse(parseTree)) != 0)
- r->isInstead = true;
- else
- r->isInstead = false;
- r->eventType = prs2FindEventTypeFromParse(parseTree);
-
- /*
- *
- * Find the OID of the relation to be locked, and the
- * attribute number of the locked attribute. If no such
- * attribute has been specified, use 'InvalidAttributeNumber'
- * instead.
- *
- * NOTE: 'eventTarget' is a list of one or two items.
- * The first one is the name of the relation and the optional second
- * one is the attribute name
- *
- * XXX: this should change in the future! It would be better
- * that the parser will return a list with the relation OID
- * and the attibute number instead of their names!
- */
- eventTarget = GetRuleEventTargetFromParse(parseTree);
- strcpy(r->eventRelationName->data, CString(CAR(eventTarget)));
- rel = RelationNameGetRelation(r->eventRelationName);
- r->eventRelationOid = rel->rd_id;
- if (null(CDR(eventTarget))) {
- /*
- * no attribute is specified
- */
- r->eventAttributeNumber = InvalidAttributeNumber;
- r->eventAttributeName = NULL;
- } else {
- strcpy(r->eventAttributeName->data, CString(CADR(eventTarget)));
- r->eventAttributeNumber = get_attnum(r->eventRelationOid,
- r->eventAttributeName);
- if (r->eventAttributeNumber == InvalidAttributeNumber) {
- elog(WARN,"Illegal attribute in event target list");
- }
- /*
- * XXX currently we only allow tuple-level rules to
- * be defined in attributes of basic types (i.e. not of type
- * relation etc....)
- */
- if (!prs2AttributeIsOfBasicType(r->eventRelationOid,
- r->eventAttributeNumber)) {
- elog(WARN,
- "Can not define tuple rules in non-base type attributes");
- }
- /*
- * "on delete" and "on append" rules must not have an attribute
- * specified in the event clause.
- */
- if (r->eventType == EventTypeDelete)
- elog(WARN,
- "On Delete rules must not have an attribute in their event clause");
- if (r->eventType == EventTypeAppend)
- elog(WARN,
- "On Append rules must not have an attribute in their event clause");
- }
-
- /*
- * check if we use CURRENT on a 'on append' rule, or NEW
- * on a 'on retrieve' or 'on delete' rule.
- * If yes, then complain...
- */
- r->ruleQual = GetRuleQualFromParse(parseTree);
- r->ruleAction = GetRuleActionFromParse(parseTree);
- IsPlanUsingNewOrCurrent(r->ruleQual, ¤tUsed, &newUsed);
- if (currentUsed && r->eventType == EventTypeAppend) {
- elog(WARN,
- "An `on append' rule, can not reference the 'current' tuple");
- }
- if (newUsed && r->eventType == EventTypeRetrieve) {
- elog(WARN,
- "An `on retrieve' rule, can not reference the 'new' tuple");
- }
- if (newUsed && r->eventType == EventTypeDelete) {
- elog(WARN,
- "An `on delete' rule, can not reference the 'new' tuple");
- }
- IsPlanUsingNewOrCurrent(r->ruleAction, ¤tUsed, &newUsed);
- if (currentUsed && r->eventType == EventTypeAppend) {
- elog(WARN,
- "An `on append' rule, can not reference the 'current' tuple");
- }
- if (newUsed && r->eventType == EventTypeRetrieve) {
- elog(WARN,
- "An `on retrieve' rule, can not reference the 'new' tuple");
- }
- if (newUsed && r->eventType == EventTypeDelete) {
- elog(WARN,
- "An `on delete' rule, can not reference the 'new' tuple");
- }
-
- /*
- * The parsetree generated by the parser has a NEW and/or CURRENT
- * entries in the range table. In order to find the rule qualification
- * and the action plans to be executed at rule activation time,
- * we have to change all the corresponding "Var" nodes to the
- * appropriate "Param" nodes.
- * Note however, that we must also keep the original rule qualification
- * (i.e. the one with the "Var" nodes) because it is needed to
- * calculate the appropriate stub records etc.
- * nodes to the equivalent
- */
- r->paramParseTree = lispCopy(parseTree);
- SubstituteParamForNewOrCurrent(r->paramParseTree, r->eventRelationOid);
- r->paramRuleQual = GetRuleQualFromParse(r->paramParseTree);
- r->paramRuleAction = GetRuleActionFromParse(r->paramParseTree);
-
- /*
- * Now, find the type of action. (i.e. ActionTypeRetrieve,
- * ActionTypeReplaceCurrent or ActionTypeOther).
- * In the first 2 cases, `updatedAttributeNumber' is the number
- * of attribute beeing updated.
- */
- r->actionType = prs2FindActionTypeFromParse(r->parseTree,
- r->eventAttributeNumber,
- &(r->updatedAttributeNumber),
- r->eventType);
- /*
- * Hm... for the time being we do NOT allow
- * ON RETRIEVE ... DO RETRIEVE ....
- * rules without an INSTEAD
- * unless this is a "view" rule (i.e. something
- * like "on retrieve to TOYEMP do retrieve...")
- * In this case the event target object must be a
- * relation and not a "relation.attribute"
- */
- if (!(r->isInstead) && r->actionType == ActionTypeRetrieveValue &&
- r->eventAttributeNumber != InvalidAttributeNumber ) {
- elog(WARN,
- "`on retrieve ... do retrieve' tuple rules must have an `instead'");
- }
-
-
- #ifdef PRS2_DEBUG
- {
- printf("PRS2: ---DEFINE TUPLE RULE:\n");
- printf("PRS2: RuleName = %s\n", r->ruleName->data);
- printf("PRS2: event type = %d ", r->eventType);
- switch (r->eventType) {
- case EventTypeRetrieve:
- printf("(retrieve)\n");
- break;
- case EventTypeReplace:
- printf("(replace)\n");
- break;
- case EventTypeAppend:
- printf("(append)\n");
- break;
- case EventTypeDelete:
- printf("(delete)\n");
- break;
- default:
- printf("(*** UNKNOWN ***)\n");
- }
- printf("PRS2: event target:");
- lispDisplay(eventTarget);
- printf("\n");
- printf("PRS2: event target relation OID = %ld\n", r->eventRelationOid);
- printf("PRS2: event target attr no = %d\n", r->eventAttributeNumber);
- printf("PRS2: Instead flag = %d\n", r->isInstead);
- printf("PRS2: ruleAction:");
- lispDisplay(r->paramRuleAction);
- printf("\n");
- }
- #endif PRS2_DEBUG
-
- return(r);
- }
-
-
- /*-----------------------------------------------------------------------
- *
- * prs2InsertRuleInfoInCatalog
- *
- * Insert information about a rule in the rules system catalog.
- * As the rule names are unique, we have first to make sure
- * that no other rule with the same names exists.
- *
- *-----------------------------------------------------------------------
- */
- ObjectId
- prs2InsertRuleInfoInCatalog(r)
- Prs2RuleData r;
- {
- register i;
- Relation prs2RuleRelation;
- HeapTuple heapTuple;
- char *values[Prs2RuleRelationNumberOfAttributes];
- char nulls[Prs2RuleRelationNumberOfAttributes];
- ObjectId objectId;
- HeapScanDesc heapScan;
- ScanKeyEntryData ruleNameKey[1];
-
-
-
- /*
- * Open the system catalog relation
- * where we keep the rule info (pg_prs2rule)
- */
- prs2RuleRelation = RelationNameOpenHeapRelation(Prs2RuleRelationName);
- if (!RelationIsValid(prs2RuleRelation)) {
- elog(WARN, "prs2InsertRuleInfoCatalog: could not open relation %s",
- Prs2RuleRelationName);
- }
-
- /*
- * First make sure that no other rule with the same name exists!
- */
- ScanKeyEntryInitialize(&ruleNameKey[0], 0, Prs2RuleNameAttributeNumber,
- F_CHAR16EQ, NameGetDatum(r->ruleName));
-
- heapScan = RelationBeginHeapScan(prs2RuleRelation, false, NowTimeQual,
- 1, (ScanKey) ruleNameKey);
- heapTuple = HeapScanGetNextTuple(heapScan, false, (Buffer *) NULL);
- if (HeapTupleIsValid(heapTuple)) {
- HeapScanEnd(heapScan);
- RelationCloseHeapRelation(prs2RuleRelation);
- elog(WARN, "Sorry, rule %s is already defined",
- r->ruleName);
- }
- HeapScanEnd(heapScan);
-
- /*
- * Now create a tuple with the new rule info
- */
- for (i = 0; i < Prs2RuleRelationNumberOfAttributes; ++i) {
- values[i] = NULL;
- nulls[i] = 'n';
- }
-
- values[Prs2RuleNameAttributeNumber-1] =
- fmgr(F_CHAR16IN,(char *)(r->ruleName));
- nulls[Prs2RuleNameAttributeNumber-1] = ' ';
-
- values[Prs2RuleEventTypeAttributeNumber-1] = (char *) r->eventType;
- nulls[Prs2RuleEventTypeAttributeNumber-1] = ' ';
-
- values[Prs2RuleEventTargetRelationAttributeNumber-1] =
- (char *) r->eventRelationOid;
- nulls[Prs2RuleEventTargetRelationAttributeNumber-1] = ' ';
-
- values[Prs2RuleEventTargetAttributeAttributeNumber-1] =
- (char *) r->eventAttributeNumber;
- nulls[Prs2RuleEventTargetAttributeAttributeNumber-1] = ' ';
-
- values[Prs2RuleTextAttributeNumber-1] =
- fmgr(F_TEXTIN, r->ruleText);
- nulls[Prs2RuleTextAttributeNumber-1] = ' ';
-
- heapTuple = FormHeapTuple(Prs2RuleRelationNumberOfAttributes,
- &prs2RuleRelation->rd_att, values, nulls);
-
- /*
- * Now insert the tuple in the system catalog
- * and return its OID (which form now on is the rule's id.
- */
- (void) RelationInsertHeapTuple(prs2RuleRelation, heapTuple,
- (double *) NULL);
- objectId = heapTuple->t_oid;
- RelationCloseHeapRelation(prs2RuleRelation);
- return(objectId);
- }
-
- /*-----------------------------------------------------------------------
- * prs2DeleteRuleInfoFromCatalog
- *
- * remove all rule info stored in 'pg_prs2rule' about the given
- * rule.
- *
- *-----------------------------------------------------------------------
- */
- void
- prs2DeleteRuleInfoFromCatalog(ruleId)
- ObjectId ruleId;
- {
- Relation prs2RuleRelation;
- HeapScanDesc scanDesc;
- ScanKeyData scanKey;
- HeapTuple tuple;
- Buffer buffer;
-
- /*
- * Open the pg_rule relation.
- */
- prs2RuleRelation = RelationNameOpenHeapRelation(Prs2RuleRelationName);
-
- /*
- * Scan the RuleRelation ('pg_prs2rule') until we find a tuple
- */
- ScanKeyEntryInitialize(&scanKey.data[0], 0, ObjectIdAttributeNumber,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(ruleId));
-
- scanDesc = RelationBeginHeapScan(prs2RuleRelation,
- false, NowTimeQual, 1, &scanKey);
-
- tuple = HeapScanGetNextTuple(scanDesc, false, &buffer);
-
- /*
- * complain if no such rule existed
- */
- if (!HeapTupleIsValid(tuple)) {
- RelationCloseHeapRelation(prs2RuleRelation);
- elog(WARN, "No rule with id = '%d' was found.\n", ruleId);
- }
-
- /*
- * Now delete the tuple...
- */
- RelationDeleteHeapTuple(prs2RuleRelation, &(tuple->t_ctid));
- RelationCloseHeapRelation(prs2RuleRelation);
- HeapScanEnd(scanDesc);
- }
-
- /*-----------------------------------------------------------------------
- *
- * prs2InsertRulePlanInCatalog
- *
- * Insert a rule plan into the appropriate system catalogs.
- * Arguments:
- * ruleId the OID of the rule (as returned by routine
- * 'prs2InsertRuleInfoInCatalog').
- * planNumber the corresponding planNumber.
- * rulePlan the rule plan itself!
- *
- *-----------------------------------------------------------------------
- */
- void
- prs2InsertRulePlanInCatalog(ruleId, planNumber, rulePlan)
- ObjectId ruleId;
- Prs2PlanNumber planNumber;
- List rulePlan;
- {
- register i;
- char *rulePlanString;
- Relation prs2PlansRelation;
- HeapTuple heapTuple;
- char *values[Prs2PlansRelationNumberOfAttributes];
- char nulls[Prs2PlansRelationNumberOfAttributes];
-
-
- /*
- * Open the system catalog relation
- */
- prs2PlansRelation=RelationNameOpenHeapRelation(Prs2PlansRelationName);
- if (!RelationIsValid(prs2PlansRelation)) {
- elog(WARN, "prs2InsertRulePlanInCatalog: could not open relation %s",
- Prs2PlansRelationName);
- }
-
- /*
- * Create the appropriate tuple.
- * NOTE: 'rulePlan' is of type LispValue, so we have first
- * to transform it to a string using 'PlanToString()'
- */
- rulePlanString = PlanToString(rulePlan);
-
- for (i = 0; i < Prs2PlansRelationNumberOfAttributes; ++i) {
- nulls[i] = ' ';
- }
-
- values[Prs2PlansRuleIdAttributeNumber-1] = (char *) ruleId;
- values[Prs2PlansPlanNumberAttributeNumber-1] = (char *) planNumber;
- values[Prs2PlansCodeAttributeNumber-1] = fmgr(F_TEXTIN,rulePlanString);
-
- heapTuple = FormHeapTuple(Prs2PlansRelationNumberOfAttributes,
- &prs2PlansRelation->rd_att, values, nulls);
-
- /*
- * Now insert the tuple to the system catalog.
- */
- (void) RelationInsertHeapTuple(prs2PlansRelation,
- heapTuple, (double *) NULL);
- RelationCloseHeapRelation(prs2PlansRelation);
- pfree(rulePlanString);
-
- }
-
- /*--------------------------------------------------------------------------
- * prs2DeleteRulePlanFromCatalog
- *
- * Delete all rule plans for the given rule from the "pg_prs2plans"
- * system catalog.
- *--------------------------------------------------------------------------
- */
- void
- prs2DeleteRulePlanFromCatalog(ruleId)
- ObjectId ruleId;
- {
- Relation prs2PlansRelation;
- HeapScanDesc scanDesc;
- ScanKeyData scanKey;
- HeapTuple tuple;
- Buffer buffer;
-
- /*
- * Delete all tuples of the Prs2Plans relation (pg_prs2plans)
- * corresponding to this rule...
- */
- prs2PlansRelation = RelationNameOpenHeapRelation(Prs2PlansRelationName);
-
- ScanKeyEntryInitialize(&scanKey.data[0], 0, Prs2PlansRuleIdAttributeNumber,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(ruleId));
-
- scanDesc = RelationBeginHeapScan(prs2PlansRelation,
- false, NowTimeQual, 1, &scanKey);
-
-
- while((tuple=HeapScanGetNextTuple(scanDesc,false,(Buffer *)NULL)) !=NULL) {
- /*
- * delete the prs2PlansRelation tuple...
- */
- RelationDeleteHeapTuple(prs2PlansRelation, &(tuple->t_ctid));
- }
-
- RelationCloseHeapRelation(prs2PlansRelation);
- HeapScanEnd(scanDesc);
-
- }
-
- /*----------------------------------------------------------------------
- *
- * prs2GenerateActionPlans
- *
- * generate the plan+parse trees for the action part of the rule
- *
- *----------------------------------------------------------------------
- */
- LispValue
- prs2GenerateActionPlans(r)
- Prs2RuleData r;
- {
- LispValue result;
- LispValue action;
- LispValue oneParse;
- LispValue onePlan;
- LispValue oneEntry;
- LispValue qualQuery;
- LispValue ruleInfo;
- LispValue rangeTable;
- AttributeNumber currentAttributeNo;
-
-
- rangeTable = GetRuleRangeTableFromParse(r->parseTree);
-
- /*
- * the first entry in the result is some rule info
- * This consists of the following fields:
- * a) "instead" or "not-instead"
- * b) the attribute number of the attribute specified
- * in the ON EVENT TO REL.attribute clause
- * (or InvalidAttributeNumber)
- * c) either InvalidAttributeNumber, or in the case of a rule
- * of the form:
- * ON REPLACE TO REL.x WHERE ....
- * DO REPLACE CURRENT.attribute
- * the 'attribute' that is replced by the rule.
- */
- if (r->isInstead) {
- ruleInfo = lispCons(lispString("instead"), LispNil);
- } else {
- ruleInfo = lispCons(lispString("not-instead"), LispNil);
- }
-
- ruleInfo = nappend1(ruleInfo, lispInteger(r->eventAttributeNumber));
- ruleInfo = nappend1(ruleInfo, lispInteger(r->updatedAttributeNumber));
-
- result = lispCons(ruleInfo, LispNil);
-
-
- /*
- * now append the qual entry (parse tree + plan)
- */
- if (null(r->ruleQual)) {
- oneEntry = LispNil;
- } else {
- /*
- * the 'ruleQual' is just a qualification.
- * Transform it into a query of the form:
- * "retrieve (foo=1) where QUAL".
- * The rule manager will run this query and if there is
- * a tuple returned, then we know that the qual is true,
- * otherwise we know it is false
- */
- LispValue MakeRoot();
- LispValue root, targetList;
- Resdom resdom;
- Const constant;
- Name name;
- Datum value;
-
- /*
- * construct the target list
- */
- name = (Name) palloc(sizeof(NameData));
- if (name == NULL) {
- elog(WARN, "prs2GenerateActionPlans: Out of memory");
- }
- strcpy(name->data,"foo");
- resdom = MakeResdom((AttributeNumber)1,
- (ObjectId) 23,
- false,
- (Size) 4,
- name,
- (Index) 0,
- (OperatorTupleForm) 0,
- 0);
- value = Int32GetDatum(1);
- constant = MakeConst((ObjectId) 23, /* type */
- (Size) 4, /* size */
- value, /* value */
- false, /* isnull */
- true); /* byval */
- targetList = lispCons(
- lispCons((LispValue)resdom,
- lispCons((LispValue)constant, LispNil)),
- LispNil);
- /*
- * now the root
- * XXX NumLevels == 1 ??? IS THIS CORRECT ????
- */
- root = MakeRoot(
- 1, /* num levels */
- lispAtom("retrieve"), /* command */
- LispNil, /* result relation */
- rangeTable, /* range table */
- lispInteger(0), /* priority */
- LispNil, /* rule info */
- LispNil, /* unique flag */
- LispNil, /* sort_clause */
- targetList); /* targetList */
- /*
- * Finally, construct the parse tree...
- */
- qualQuery = lispCons(root,
- lispCons(targetList,
- lispCons(r->paramRuleQual, LispNil)));
- onePlan = planner(qualQuery);
- oneEntry = lispCons(onePlan, LispNil);
- oneEntry = lispCons(qualQuery, oneEntry);
- }
- result = nappend1(result, oneEntry);
-
- /*
- * Now for each action append the corresponding entry
- * (parse tree + plan)
- */
- foreach (action, r->paramRuleAction) {
- oneParse = CAR(action);
- /*
- * XXX: THIS IS A HACK !!!
- * (but it works, so what the hell....)
- *
- * if this is a REPLACE CURRENT (X = ...)
- * change it to a RETRIEVE (X = ...)
- */
- changeReplaceToRetrieve(oneParse);
- /*
- * call the planner to create a plan for this parse tree
- */
- onePlan = planner(oneParse);
- oneEntry = lispCons(onePlan, LispNil);
- oneEntry = lispCons(oneParse, oneEntry);
- result = nappend1(result, oneEntry);
- }
-
- /*
- * finally insert itn the beginning of the list the
- * string Prs2RulePlanType_ACTION to show that this is
- * an action plan (as opposed to an import/export plan).
- */
- result = lispCons(lispString(Prs2RulePlanType_ACTION), result);
-
- return(result);
- }
-
- /*------------------------------------------------------------------
- *
- * prs2FindEventTypeFromParse
- *
- * Given a rule's parse tree find its event type.
- *------------------------------------------------------------------
- */
- EventType
- prs2FindEventTypeFromParse(parseTree)
- LispValue parseTree;
- {
-
- int eventTypeInt;
- EventType eventType;
-
- eventTypeInt = CInteger(GetRuleEventTypeFromParse(parseTree));
-
- /*
- * Note that the event type as stored in the parse tree is one of
- * RETRIEVE, REPLACE, APPEND or DELETE. All these symbols are
- * defined in "parse.h". So, we have to change them
- * into the appropriate "EventType" type.
- */
- switch (eventTypeInt) {
- case RETRIEVE:
- eventType = EventTypeRetrieve;
- break;
- case REPLACE:
- eventType = EventTypeReplace;
- break;
- case APPEND:
- eventType = EventTypeAppend;
- break;
- case DELETE:
- eventType = EventTypeDelete;
- break;
- default:
- eventType = EventTypeInvalid;
- elog(WARN, "prs2DefineTupleRule: Illegal event type (int) %d",
- eventTypeInt);
- } /* switch*/
-
- return(eventType);
- }
-
- /*------------------------------------------------------------------
- *
- * prs2FindActionTypeFromParse
- *
- * find the ActionType of a rule.
- *
- * if the action is in the form 'REPLACE CURRENT(x = ....)'
- * then (*updatedAttributeNumber) is the attribute number of the
- * updated field, otherwise it is InvalidAttributeNumber.
- *------------------------------------------------------------------
- */
- ActionType
- prs2FindActionTypeFromParse(parseTree,
- eventTargetAttributeNumber,
- updatedAttributeNumberP,
- eventType)
- LispValue parseTree;
- AttributeNumber eventTargetAttributeNumber;
- AttributeNumberPtr updatedAttributeNumberP;
- EventType eventType;
- {
-
- LispValue ruleActions;
- LispValue t, oneRuleAction;
- LispValue root;
- int commandType;
- LispValue resultRelation;
- LispValue rangeTable;
- ActionType actionType;
- Name relationName;
- NameData nameData;
- LispValue targetList;
- int resultRelationNo;
- LispValue resultRelationEntry;
-
- *updatedAttributeNumberP = InvalidAttributeNumber;
-
- ruleActions = GetRuleActionFromParse(parseTree);
-
- if (null(ruleActions)) {
- if (eventType != EventTypeRetrieve) {
- /*
- * then this is probably an `instead' rule with no action
- * specified, e.g. "ON delete to DEPT WHERE ... DO INSTEAD"
- */
- return(ActionTypeOther);
- } else {
- /*
- * However, if we have something like:
- * ON RETRIEVE THEN DO INSTEAD NOTHING
- * we assume that this means do NOT retrieve a value,
- * i.e. return a null attribute.
- */
- *updatedAttributeNumberP = eventTargetAttributeNumber;
- return(ActionTypeRetrieveValue);
- }
- }
-
- foreach(t, ruleActions) {
- oneRuleAction = CAR(t);
- /*
- * find the type of query (retrieve, delete etc...)
- */
- root = parse_root(oneRuleAction);
- commandType = root_command_type(root);
- resultRelation = root_result_relation(root);
- rangeTable = root_rangetable(root);
- if (!null(resultRelation)) {
- if (commandType == RETRIEVE) {
- /*
- * This is a retrieve into, the result reln info
- * is a list of junk.
- */
- strncpy(&(nameData.data[0]),
- CString(CADR(resultRelation)), sizeof(NameData));
- } else {
- resultRelationNo = CInteger(resultRelation);
- resultRelationEntry = nth(resultRelationNo-1, rangeTable);
- strcpy(&(nameData.data[0]),
- CString(rt_relname(resultRelationEntry)));
- }
- relationName = &nameData;
- } else {
- relationName = InvalidName;
- }
- if (commandType == RETRIEVE && null(resultRelation)) {
- /*
- * this is a "retrieve" (NOT a "retrieve into...")
- * action.
- * It can be either something like:
- * ON retrieve to EMP.salary
- * WHERE ....
- * DO retrieve (salary = ....) where .....
- *
- * In which case only one 'retrieve' command is allowed
- * in the action part of the rule,
- * or it can be a view type rule:
- * ON retrieve to TOYEMP
- * DO retrieve (EMP.all) where EMP.dept = "toy"
- */
- actionType = ActionTypeRetrieveValue;
- break; /* exit 'foreach' loop */
-
- } else if (commandType == REPLACE &&
- /*
- * Dangerous cast - it just happens that NameIsEqual()
- * currently calls strncmp()
- */
- NameIsEqual((Name)"*CURRENT*", relationName)) {
- /*
- * this is a replace CURRENT(...)
- */
- actionType = ActionTypeReplaceCurrent;
- /*
- * find the updated attribute number...
- */
- targetList = parse_targetlist(oneRuleAction);
- if (ExecTargetListLength(targetList) != 1) {
- elog(WARN,
- " a 'replace CURRENT(...)' must replace ONLY 1 attribute");
- }
- *updatedAttributeNumberP =
- get_resno((Resdom)tl_resdom(CAR(targetList)));
- break; /* exit 'foreach' loop */
- } else if (commandType == REPLACE &&
- NameIsEqual((Name)"*NEW*", relationName)) {
- /*
- * this is a replace NEW(...)
- */
- actionType = ActionTypeReplaceNew;
- /*
- * find the updated attribute number...
- */
- targetList = parse_targetlist(oneRuleAction);
- if (ExecTargetListLength(targetList) != 1) {
- elog(WARN,
- " a 'replace NEW(...)' must replace ONLY 1 attribute");
- }
- *updatedAttributeNumberP =
- get_resno((Resdom)tl_resdom(CAR(targetList)));
- break; /* exit 'foreach' loop */
- } else {
- actionType = ActionTypeOther;
- }
- } /* foreach */
-
- if (actionType == ActionTypeRetrieveValue) {
- /*
- * then this must be the ONLY statement in the rule actions!
- */
- if (length(ruleActions) != 1) {
- elog(WARN,
- "a 'retrieve (..)' must be the only action of a PRS2 rule!");
- }
- *updatedAttributeNumberP = eventTargetAttributeNumber;
- }
-
- if (actionType == ActionTypeReplaceCurrent) {
- /*
- * then this must be the ONLY statement in the rule actions!
- */
- if (length(ruleActions) != 1) {
- elog(WARN,
- "a 'replace CURRENT(..)' must be the only action of a PRS2 rule!");
- }
- }
-
- if (actionType == ActionTypeReplaceNew) {
- /*
- * then this must be the ONLY statement in the rule actions!
- */
- if (length(ruleActions) != 1) {
- elog(WARN,
- "a 'replace NEW(..)' must be the only action of a PRS2 rule!");
- }
- }
-
- return(actionType);
- }
-
- /*----------------------------------------------------------------
- *
- * changeReplaceToRetrieve
- *
- * Ghange the parse tree of a 'REPLACE CURRENT(X = ...)'
- * or 'REPLACE NEW(X = ...)' command to a
- * 'RETRIEVE (X = ...)'
- *----------------------------------------------------------------
- */
- void
- changeReplaceToRetrieve(parseTree)
- LispValue parseTree;
- {
-
- LispValue root;
- LispValue targetList;
- int commandType;
- LispValue resultRelation;
- LispValue rangeTable;
- Name relationName;
- NameData nameData;
- int resultRelationNo;
- LispValue resultRelationEntry;
-
-
- root = parse_root(parseTree);
- commandType = root_command_type(root);
- resultRelation = root_result_relation(root);
- rangeTable = root_rangetable(root);
- if (!null(resultRelation)) {
- if (commandType == RETRIEVE) {
- /*
- * This is a retrieve into, the result reln info
- * is a list of junk.
- */
- strncpy(&(nameData.data[0]),
- CString(CADR(resultRelation)), sizeof(NameData));
- } else {
- resultRelationNo = CInteger(resultRelation);
- resultRelationEntry = nth(resultRelationNo-1, rangeTable);
- strcpy(&(nameData.data[0]),
- CString(rt_relname(resultRelationEntry)));
- }
- relationName = &nameData;
- } else {
- relationName = InvalidName;
- }
-
- /*
- * Is this a REPLACE CURRENT command?
- */
- if (commandType!=REPLACE ||
- (!NameIsEqual((Name)"*CURRENT*", relationName) &&
- !NameIsEqual((Name)"*NEW*", relationName))) {
- /*
- * NO, this is not a REPLACE CURRENT or a REPLACE NEW command
- */
- return;
- }
-
- /*
- * Yes it is!
- *
- * Now *DESTRUCTIVELY* change the parse tree...
- *
- * Change the command from 'replace' to 'retrieve'
- * and the result relation to 'nil'
- */
- root = parse_root(parseTree);
- root_command_type_atom(root) = lispAtom("retrieve");
- root_result_relation(root) = LispNil;
-
- /*
- * Now go to the target list (which must have exactly 1 Resdom
- * node, and change the 'resno' to 1
- */
- targetList = parse_targetlist(parseTree);
- set_resno((Resdom)tl_resdom(CAR(targetList)), (AttributeNumber)1);
- }
-
- /*-----------------------------------------------------------------
- *
- * prs2AttributeIsOfBasicType
- *
- * check if the given attribute is of a "basic" type.
- *-----------------------------------------------------------------
- */
- bool
- prs2AttributeIsOfBasicType(relOid, attrNo)
- ObjectId relOid;
- AttributeNumber attrNo;
- {
- ObjectId typeId;
- char typtype;
-
- typeId = get_atttype(relOid, attrNo);
- typtype = get_typtype(typeId);
- if (typtype == '\0') {
- elog(WARN, "Cache lookup for type %ld failed...", typeId);
- }
-
- if (typtype == 'b') {
- return(true);
- } else {
- return(false);
- }
- }
-
- /*=============================== DEBUGGINF STUFF ================*/
- LispValue
- prs2ReadRule(fname)
- char *fname;
- {
- FILE *fp;
- int c;
- int count, maxcount;
- char *s1, *s2;
- LispValue l;
- LispValue StringToPlan();
-
- printf("--- prsReadRule.\n");
- AllocateFile();
- if (fname==NULL) {
- fp = stdin;
- printf(" reading rule from stdin.\n");
- } else {
- AllocateFile();
- fp = fopen(fname, "r");
- if (fp==NULL){
- printf(" Can not open rule file %s\n", fname);
- elog(WARN,"prs2ReadRule.... exiting...\n");
- } else {
- printf("Reading rule from file %s\n", fname);
- }
- }
-
- maxcount = 100;
- s1 = palloc(maxcount);
- if (s1 == NULL) {
- elog(WARN,"prs2ReadRule : out of memory!");
- }
-
- count = 0;
- while((c=getc(fp)) != EOF) {
- if (count >= maxcount) {
- maxcount = maxcount + 1000;
- s2 = palloc(maxcount);
- if (s2 == NULL) {
- elog(WARN,"prs2ReadRule : out of memory!");
- }
- bcopy(s1, s2, count);
- pfree(s1);
- s1 = s2;
- }
- s1[count] = c;
- count++;
- }
- s1[count+1] = '\0';
-
- l = StringToPlan(s1);
-
- printf(" list = \n");
- lispDisplay(l);
-
- if (fp!=stdin) {
- fclose(fp);
- FreeFile();
- }
-
- return(l);
- }
-